# 读取文件的驱动(Excel、Yaml)
import yaml,os
from xlrd import open_workbook,xldate_as_tuple
from datetime import datetime

class Yaml():
    # 读取配置文件yaml文件成配置内容,并返回列表嵌套字典
    def __init__(self, yamlPath):
        if os.path.exists(yamlPath):
            self.yamlPath = yamlPath
        else:
            raise FileNotFoundError('文件不存在！')
        self._data = None
    @property
    def data(self):
        # 如果是第一次调用data，读取yaml文档，否则直接返回之前保存的数据
        if not self._data:
            file =open(self.yamlPath, 'rb')
            with file as f:
                self._data = list(yaml.safe_load_all(f))  # load后是个generator，用list组织成列表
                file.close()
        return self._data




class SheetTypeError(Exception):
    pass

class Excle():
    def __init__(self, excelpath,sheet,col):
        if os.path.exists(excelpath):
            self.excelpath = excelpath  # excel文件路径
        else:
            raise FileNotFoundError('文件不存在！')
        self.sheet = sheet  # sheet可以是int表示表格的索引，可以是str表示表格的名称
        self._data = list()  # 用于存储每行生成的数据
        self.cols = col #读取Excel的列数
    @property
    def data(self):
        if  not self._data:
            workbook = open_workbook(self.excelpath)    #打开excel
            # 判断是索引还是sheet名称
            if type(self.sheet) not in [int, str]:
                #用raise语句来引发一个异常。异常/错误对象必须有一个名字，且它们应是Error或Exception类的子类。
                raise SheetTypeError('Please pass in <type int> or <type str>, not {0}'.format(type(self.sheet)))
            elif type(self.sheet) == int:
                s = workbook.sheet_by_index(self.sheet)
            else:
                s = workbook.sheet_by_name(self.sheet)
            rows = s.nrows  # 获取行数
            cols = self.cols  # 获取列数，
            dict = {}  # 声明一个字典

            for i in range(rows):  # 行
                for j in range(cols):  # 列
                    cell = s.cell_value(i, j)  # 将每行的列赋值给cell
                    ctype = s.cell(i, j).ctype  # 获取列的类型
                    if j == 0:
                        try:
                            id = int(cell)  # 以第一列做键值
                        except ValueError as e:
                            id = cell
                            dict[id] = []
                    if ctype == 3:  # 若是日期格式转换为固定格式
                        date = datetime(*xldate_as_tuple(cell, 0))
                        cell = date.strftime('%Y-%n-%d')
                    else:
                        pass
                    dict[id].append(cell)  # 将每行中的列的数据存入字典中，且以每行的第一列为键

            return dict

'''
判断是否有title，如果有返回字典类型，如果没有title，则将第一列做为字典的键，返回字典类型
'''
class ExcelReader():
    """
    如：
    excel中内容为：
    | A1 | B1 | C1 |
    | A2 | B2 | C2 |

    如果 print(ExcelReader(excel, title_line=True).data)，输出结果：
    [{A: A1, B: B1, C:C1}, {A:A2, B:B2, C:C2}]

    如果 print(ExcelReader(excel, title_line=False).data)，输出结果：
    {A: A1, B: B1, C:C1}

    可以指定sheet，通过index或者name：
    ExcelReader(excel, sheet=2)
    ExcelReader(excel, sheet='BaiDuTest')
    """
    def __init__(self, excelpath, sheet, title_line):
        if os.path.exists(excelpath):
            self.excelpath = excelpath  # excel文件路径
        else:
            raise FileNotFoundError('文件不存在！')
        self.sheet = sheet   # sheet可以是int表示表格的索引，可以是str表示表格的名称
        self.title_line = title_line  # 是否存在标题行，有标题行，每一行都是都是对应列名的取值；没有标题行，每一行都是一个列表
        self._data = list()   # 用于存储每行生成的数据。

    @property
    def data(self):
        if  not self._data:
            workbook = open_workbook(self.excelpath)    #打开excel
            # 判断是索引还是sheet名称
            if type(self.sheet) not in [int, str]:
                #用raise语句来引发一个异常。异常/错误对象必须有一个名字，且它们应是Error或Exception类的子类。
                raise SheetTypeError('Please pass in <type int> or <type str>, not {0}'.format(type(self.sheet)))
            elif type(self.sheet) == int:
                s = workbook.sheet_by_index(self.sheet)
            else:
                s = workbook.sheet_by_name(self.sheet)
            if self.title_line:
                #有title，返回列表嵌套字典，如：[{1:'a},{2:'b}]
                title = s.row_values(0)  # 首行为title
                for col in range(1, s.nrows):
                    # 依次遍历其余行，与首行组成dict，拼到self._data中
                    self._data.append(dict(zip(title, s.row_values(col))))
                return self._data

            else:
                # 没有title，返回字典类型
                for col in range(0, s.nrows):
                    # 遍历所有行，拼到self._data中
                    # self._data.append(s.row_values(col)) #得到的结果是一个双重列表，如：[[1],[2]]
                    col1 = s.col_values(0)  #获取第一列的内容
                    col2 = s.col_values(1)  # 获取第二列的内容
                    data_ = dict(zip(col1, col2))
                return data_